package cn.autumnorange.app.common.consumerproducer.util;

import org.springframework.core.LocalVariableTableParameterNameDiscoverer;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ClassUtil {

  //  public static Object getFieldObjByClass(Object targetObj, String cacheFeildName)
  //      throws IllegalAccessException {
  //    Object fieldObj=null;
  //    // 找字段名跟注解字段名相同的字段
  //    Field[] fields = ClassUtil.getAllFields(targetObj.getClass());
  //    for (Field field : fields) {
  //      if (!field.isAccessible()) {
  //        field.setAccessible(true);
  //      }
  //      if (field.getName().equals(cacheFeildName)) {
  //        System.out.println(
  //            field.getType().getName() + "  " + field.getName() + "   " + field.get(targetObj));
  //        return field.get(targetObj);
  //      } else {
  //        fieldObj=getFieldObjByClass(field.get(targetObj), cacheFeildName);
  //        if(fieldObj!=null){
  //          return fieldObj;
  //        }
  //      }
  //    }
  //    return null;
  //  }

  /**
   * 通过指定对象每层字段名存入有序列表feildNames来找到对应注解的值
   *
   * @param targetObj
   * @param feildNames orderID#ctpuID[5]#materialID
   * @return
   * @throws IllegalAccessException
   */
  public static Object getFieldObjByClass(Object targetObj, List<String> feildNames)
      throws IllegalAccessException {
    return getFieldObjByClass(targetObj, feildNames, 0);
  }

  public static Object getFieldObjByClass(Object targetObj, List<String> feildNames, int index)
      throws IllegalAccessException {

    Object fieldObj = null;
    // 找字段名跟注解字段名相同的字段
    Field[] fields = ClassUtil.getAllFields(targetObj.getClass());
    for (Field field : fields) {
      if (field.getName().equals(feildNames.get(index))) {
        if (!field.isAccessible()) {
          field.setAccessible(true);
        }
        fieldObj = field.get(targetObj);
        if (fieldObj == null) {
          return null;
        }
        if (index < feildNames.size() - 1) {
          fieldObj = getFieldObjByClass(fieldObj, feildNames, ++index);
        } else {
          break;
        }
      }
    }
    return fieldObj;
  }

  /**
   * @param targetClass
   * @param needCheckObj
   * @return 返回被校验对象needCheckObj Class类型=targetClass的属性字段或者包含该对象包括父类
   * @throws IllegalAccessException
   */
  public static Object getTargetObjByCheckClass(Class<?> targetClass, Object needCheckObj)
      throws IllegalAccessException {
    if (targetClass == null || needCheckObj == null) {
      return null;
    }

    Class needCheckClass = needCheckObj.getClass();
    // 校验class类型是否相等
    if (targetClass.equals(needCheckClass)) {
      return needCheckObj;
    }
    Class supperClass = needCheckClass.getSuperclass();
    while (supperClass != null) {
      if (supperClass.equals(targetClass)) {
        return needCheckObj;
      } else {
        supperClass = supperClass.getSuperclass();
      }
    }
    // 校验本对象包含父类所有字段是否与目标类型Class相同
    Field[] fields = getAllFields(needCheckClass);
    for (Field field : fields) {
      if (field.getType().equals(targetClass)) {
        if (!field.isAccessible()) {
          field.setAccessible(true);
        }
        return field.get(needCheckObj);
      }

      //            System.out.println(
      //                    field.getType().getName() + "  " + field.getName() + "   " +
      // field.get(needCheckObj));
    }
    Object result = null;
    // 从类字段再找
    for (Field field : fields) {
      if (!field.isAccessible()) {
        field.setAccessible(true);
      }
      System.out.println(field.getType().getName());

      if (field.getType().getName().equals("cn.autumnorange.app.util.api.dto.ChildrenDto2")) {
        System.out.println("equal");
      }
      result = getTargetObjByCheckClass(targetClass, field.get(needCheckObj));
      if (result != null) {
        return result;
      }
    }
    return null;
  }

  /**
   * @param clazz
   * @return 获取某个类的所有字段包括父类字段 私有 受保护
   */
  public static Field[] getAllFields(Class<?> clazz) {
    List<Field> fieldList = new ArrayList<>();
    while (clazz != null) {
      fieldList.addAll(new ArrayList(Arrays.asList(clazz.getDeclaredFields())));
      clazz = clazz.getSuperclass();
    }
    Field[] fields = new Field[fieldList.size()];
    return fieldList.toArray(fields);
  }

  public static void main(String[] args) throws IllegalAccessException, NoSuchMethodException {
    Student student = new Student();
    student.setStuClass("18001");
    student.setStuNum("19800101");
    student.setName("Tom");
    student.setAge("20");

    Class<? extends Student> clazz = student.getClass();
    Object object = student.getTargetObjByCheckClass(Student.class, student);
    if (object == student) {
      System.out.println("get Fatcher");
    }
    Field[] fields = getAllFields(object.getClass());
    for (Field field : fields) {
      if (field.getName().equals("stuClass")) {
        if (!field.isAccessible()) {
          field.setAccessible(true);
        }
        System.out.println(
            field.getType().getName() + "  " + field.getName() + "   " + field.get(student));
      }
    }
  }

  /**
   * getTargetFeildByFeildKey
   *
   * @param classAndCacheNameArray
   * @param arguments 被校验的对象数组
   * @param parameterNames
   * @return 根据Class类型classAndCacheNameArray[0] feild字段名classAndCacheNameArray[1] 获取对应该类的字段属性
   * @throws ClassNotFoundException
   * @throws IllegalAccessException
   */
  //  通过参数名-参数类型的方式查找会有多个重复情况 比如 Aaname 类TEST属性A字段anme 属性B字段属性A字段anme
  //  public static Object getTargetFeildObjByClassFieldName(
  //      String[] classAndCacheNameArray, Object[] arguments, String[] parameterNames)
  //      throws ClassNotFoundException, IllegalAccessException {
  //    Object targetField = null;
  //    Object targetObj = null;
  //    if (arguments != null && arguments.length > 0) {
  //      String className =null;
  //      String cacheFeildName = null;
  //
  //      if (classAndCacheNameArray.length > 1) {
  //        className = classAndCacheNameArray[0];
  //        cacheFeildName = classAndCacheNameArray[1];
  //      } else {
  //        cacheFeildName = classAndCacheNameArray[0];
  //
  //      }
  //      for (int i = 0; i < arguments.length; i++) {
  //        Object argument = arguments[i];
  //        // 当前入参参数数组arguments对应的参数名数组parameterNames
  //        String parameterName = parameterNames[i];
  //        if (classAndCacheNameArray.length > 1) {
  //
  //          //          注解字段名先和参数名比较,还有字段类型是否相同,都相同直接返回该对象
  //          if (parameterName.equals(cacheFeildName)
  //              && argument.getClass().getName().equals(className)) {
  //            return argument;
  //          }
  //          targetObj = ClassUtil.getTargetObjByCheckClass(Class.forName(className), argument);
  //          if (targetObj != null) {
  //            break;
  //          }
  //
  //        } else {
  //          if (parameterName.equals(cacheFeildName)) {
  //            return argument;
  //          }
  //          // classAndCacheNameArray 只有字段名,没有传入类型的情况校验字段名相同即可,按照当前对象名,当前以及父类字段字段名→当前对象字段对象的字段名检索
  //          targetField = getFieldObjByClass(argument, cacheFeildName);
  //          if (targetField != null) {
  //            break;
  //          }
  //        }
  //      }
  //      // 已找到该class类型的对象 再检索该对象包括父类的字段名即可
  //      if (targetObj != null) {
  //        // 找字段名跟注解字段名相同的字段
  //        Field[] fields = ClassUtil.getAllFields(targetObj.getClass());
  //        for (Field field : fields) {
  //          if (field.getName().equals(cacheFeildName)) {
  //            if (!field.isAccessible()) {
  //              field.setAccessible(true);
  //            }
  //            System.out.println(
  //                field.getType().getName() + "  " + field.getName() + "   " +
  // field.get(targetObj));
  //            targetField = field.get(targetObj);
  //            break;
  //          }
  //        }
  //      }
  //    }
  //    return targetField;
  //  }
  public static Object getFieldObj(Object argument, String[] feildKeys, String parameterName)
      throws IllegalAccessException {
    //          注解字段名先和参数名比较,还有字段类型是否相同,都相同直接返回该对象
    if (feildKeys.length == 1 && parameterName.equals(feildKeys[0])) {
      return argument;
    }
    return ClassUtil.getFieldObjByClass(argument, Arrays.asList(feildKeys));
  }

  public static Object getTargetFeildByFeildKey(
      String[] feildKeys, Object[] arguments, String[] parameterNames, int index)
      throws IllegalAccessException {
    Object targetObj = null;

    if (arguments != null && arguments.length > 0) {
      if (index > -1) {
        Object argument = arguments[index];
        // 当前入参参数数组arguments对应的参数名数组parameterNames
        String parameterName = parameterNames[index];
        //          注解字段名先和参数名比较,还有字段类型是否相同,都相同直接返回该对象
        return getFieldObj(argument, feildKeys, parameterName);

      } else {
        for (int i = 0; i < arguments.length; i++) {
          Object argument = arguments[i];
          // 当前入参参数数组arguments对应的参数名数组parameterNames
          String parameterName = parameterNames[i];
          targetObj = getFieldObj(argument, feildKeys, parameterName);
          if (targetObj != null) {
            return targetObj;
          }
        }
      }
    }
    return targetObj;
  }

  public static Object getTargetFeildByFeildKey(
      String[] feildKeys, Object[] arguments, String[] parameterNames)
      throws IllegalAccessException {
    return getTargetFeildByFeildKey(feildKeys, arguments, parameterNames, -1);
  }

  private static class Student extends ClassUtil {
    private String stuClass;
    private String stuNum;
    private String name;

    private String age;

    public String getStuClass() {
      return stuClass;
    }

    public void setStuClass(String stuClass) {
      this.stuClass = stuClass;
    }

    public String getStuNum() {
      return stuNum;
    }

    public void setStuNum(String stuNum) {
      this.stuNum = stuNum;
    }

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public String getAge() {
      return age;
    }

    public void setAge(String age) {
      this.age = age;
    }
  }
}
